﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Shipeng.Util;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Linq;
using YNTK.Common.Const;
using YNTK.Common.Enum;
using YNTK.Common.Filter;
using YNTK.Data.MongoDB.Repositorie;
using YNTK.Dependency;
using YNTK.DynamicApiController;
using YNTK.FriendlyException;
using YNTK.System.Entitys.Dto.Common;
using YNTK.System.Entitys.Dto.Mechanism;
using YNTK.System.Entitys.Permission;
using YNTK.System.Interfaces.Permission;
using Mapster;
using YNTK.Common.Util;
using System.ComponentModel.DataAnnotations;
using System.Linq.Expressions;
using YNTK.LinqBuilder;
using YNTK.System.Interfaces.Common;
using YNTK.Mapster;
using MongoDB.Driver;
using Yitter.IdGenerator;

namespace YNTK.System.Service.Permission
{
    /// <summary>
    /// 机构服务的实现
    /// 版 本：V1.0.0.0
    /// 版 权：云南通科科技有限公司（https://www.yntkkj.com）
    /// 作 者：李仕鹏
    /// 日 期：2022.10.07 
    /// </summary>
    [ApiDescriptionSettings(Tag = "机构管理", Name = "Mechanism", Order = 792)]
    [Route("api/[controller]")]
    public class MechanismService : IMechanismService, IDynamicApiController, ITransient
    {
        private readonly ISqlSugarRepository<MechanismEntity> _mechanismRepository;//机构仓储
        private readonly IMongoDBRepository<MechanismEntity> _mechanismMongoDbRepository;//机构mongodb仓储
        private readonly ISqlSugarRepository<ResponsibilityTargetEntity> _targetRepository;//机构职责目标仓储
        private readonly IMongoDBRepository<ResponsibilityTargetEntity> _targetMongoDbRepository;//机构职责目标mongodb仓储
        private readonly ITkUsersService _tkUsersService;//用户服务
        private readonly IFileService _fileService;//文件服务
        private readonly HttpContext _httpContext;
        private readonly SqlSugarScope db;// 核心对象：拥有完整的SqlSugar全部功能
        private readonly string _collectionName = "base_mechanisms";//mongodb中机构数据集名称
        private readonly string _target = "base_responsibilitytarget";//mongodb中机构职责目标数据集名称

        /// <summary>
        /// 构造方法依赖注入
        /// </summary>
        /// <param name="mechanismRepository">机构仓储</param>
        /// <param name="mechanismMongoDbRepository">机构mongodb仓储</param>
        /// <param name="targetRepository">机构职责目标仓储</param>
        /// <param name="targetMongoDbRepository">机构职责目标mongodb仓储</param>
        /// <param name="tkUsersService">用户服务</param>
        /// <param name="fileService">文件服务</param>
        public MechanismService(ISqlSugarRepository<MechanismEntity> mechanismRepository,
            IMongoDBRepository<MechanismEntity> mechanismMongoDbRepository,
            ISqlSugarRepository<ResponsibilityTargetEntity> targetRepository,
            IMongoDBRepository<ResponsibilityTargetEntity> targetMongoDbRepository,
            ITkUsersService tkUsersService, IFileService fileService)
        {
            _mechanismRepository = mechanismRepository;
            _mechanismMongoDbRepository = mechanismMongoDbRepository;
            _targetRepository = targetRepository;
            _targetMongoDbRepository = targetMongoDbRepository;
            _tkUsersService = tkUsersService;
            _fileService = fileService;
            db = _mechanismRepository.Context;
            _httpContext = App.HttpContext;
        }

        /// <summary>
        /// 获取机构类型
        /// </summary>
        /// <returns></returns>
        [HttpGet("gettype")]
        public TkResult<List<EnumListDto>> GetAuthorityList()
        {
            Dictionary<int, string> dic = EnumHelper.EnumToDic<MechanismTypeEnum>();
            var result = new List<EnumListDto>();
            foreach (KeyValuePair<int, string> kv in dic)
            {
                result.Add(new EnumListDto { Id = kv.Key.ToStr(), Value = kv.Key, Description = kv.Value });
            }
            return TkResult<List<EnumListDto>>.Success(result);
        }

        /// <summary>
        /// 获取机构树(查询条件、共享范围专用)
        /// </summary>
        /// <returns></returns>
        [HttpGet("trees")]
        public async Task<TkResult<List<MechanismTree>>> GetMechanismTree()
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                Expression<Func<MechanismEntity, bool>> where = m =>
                m.DeleteMark == null && m.OrganizeId == organizeId && m.EnabledMark==1;
                var data = await _mechanismMongoDbRepository.GetListAsync(_collectionName, where);
                if(!data.Any()) data = await _mechanismRepository.Entities.Where(where).ToListAsync();
                var treeList = data.Adapt<List<MechanismTree>>();
                if (treeList.Any())
                {
                    treeList = treeList.OrderBy(r => r.sortCode).ToList();
                    treeList = treeList.ToTree();
                }
                return TkResult<List<MechanismTree>>.Success(treeList);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"获取机构树发生异常发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 获取机构树结构数据
        /// </summary>
        /// <param name="query">查询机构请求模型</param>
        /// <returns></returns>
        [HttpPost("gettree")]
        public async Task<TkResult<List<MechanismTreeListDto>>> GetTree([FromBody] QueryMechanismFilterRequestModel query)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
                var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;
                //if (authenticationType != "2" && authenticationType != "3")
                //    throw YNTKException.Oh(ErrorCode.D1016);

                #region 获取机构数据
                var data=new List<MechanismEntity>();
                #region 组装查询条件
                Expression<Func<MechanismEntity, bool>> where = m =>
                m.DeleteMark == null && m.OrganizeId == organizeId;
                if (query.enabledMark == 1) where = where.And(m => m.EnabledMark == 1);
                if (query.enabledMark == 0) where = where.And(m => m.EnabledMark != 1);
                if (query.type != null) where = where.And(m => m.Type == query.type.GetHashCode());
                if (!string.IsNullOrWhiteSpace(query.keyword))
                    where = where.And(m => m.Name.Contains(query.keyword) ||
                    m.Code.Contains(query.keyword));
                #endregion

                #region 从mongodb中获取机构数据
                data = await _mechanismMongoDbRepository.GetListAsync(_collectionName, where);
                #endregion
                if (!data.Any())
                {
                    #region 从sqlserver数据库中获取机构数据
                    data = await _mechanismRepository.Entities.Where(where).ToListAsync();
                    #endregion
                }
                #endregion

                #region 处理返回数据
                var treeList = data.Adapt<List<MechanismTreeListDto>>();
                if(treeList.Any())
                {
                    var managerIds = new List<string>();
                    managerIds = treeList.Where(r => !string.IsNullOrWhiteSpace(r.managerId))
                        ?.ToList()?.Select(r => r.managerId)?.Distinct()?.ToList();
                    var managerList = await _tkUsersService.GetUserListByIds(managerIds);
                   
                    var resData = new List<MechanismTreeListDto>();
                    var rootNodes = treeList.Where(x =>string.IsNullOrWhiteSpace(x.parentId)).OrderBy(r => r.sortCode).ToList();
                    resData = rootNodes;
                    var manager = new UserEntity();
                    var base64 = new Dictionary<string, string>() { { "xxxxx", "" } };
                    resData.ForEach(root =>
                    {
                        root=Dispose(root, managerList, base64, treeList, query.headIcon);
                        if (!query.isAll && root.type == 0) root.hasChildren = false;
                        else root.hasChildren = treeList.Exists(x => x.parentId == root.id);//是否有子级
                        if (root.hasChildren)
                        {
                            root.children = GetChildren(root, treeList, managerList, base64, query.headIcon,query.isAll);
                            root.num = root.children.Count();
                        }
                        else
                        {
                            root.isLeaf = !root.hasChildren;
                            root.children = null;
                        }
                    });
                    treeList = resData;
                }
                #endregion

                return TkResult<List<MechanismTreeListDto>>.Success(treeList);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"获取机构树结构数据发生异常发生异常：{ex.Message}");
            }
        }

        private List<MechanismTreeListDto> GetChildren(MechanismTreeListDto mechanism, List<MechanismTreeListDto> nodes,
             List<UserEntity> managerList, Dictionary<string, string> base64,bool headIcon = true,bool isAll=true)
        {
            var resData = new List<MechanismTreeListDto>();
            //获取当前机构下的子级机构
            var children = nodes.Where(r => r.parentId == mechanism.id)?.OrderBy(r => r.sortCode)?.ToList();          
            if (children != null && children.Count > 0)
            {
                children.ForEach(node =>
                {
                    node = Dispose(node, managerList, base64, nodes, headIcon);
                    resData.Add(node);
                    if (!isAll && node.type == 0) node.hasChildren = false;
                    else node.hasChildren = nodes.Exists(x => x.parentId == node.id);//是否有子级
                    if (node.hasChildren)
                    {
                        node.children = GetChildren(node, nodes, managerList, base64, headIcon, isAll);
                        node.num = node.children.Count();
                    }
                    else
                    {

                        node.isLeaf = !node.hasChildren;
                        node.children = null;
                    }
                });
            }
            return resData;
        }

        private MechanismTreeListDto Dispose(MechanismTreeListDto node, List<UserEntity> managerList, 
            Dictionary<string, string> base64, List<MechanismTreeListDto> nodes,bool headIcon=true)
        {
            if (!string.IsNullOrWhiteSpace(node.parentId))
                node.allParentId = DisposeId(nodes, node.parentId);
            node.typeText = EnumHelper.GetEnumDescriptionString
            (node.type, typeof(MechanismTypeEnum));
            if (!string.IsNullOrWhiteSpace(node.managerId))
            {
                var manager = managerList?.FirstOrDefault(r => r.Id == node.managerId);
                node.managerName = manager?.RealName;
                node.headIcon = manager?.HeadIcon;
                if (!string.IsNullOrWhiteSpace(node.headIcon) && headIcon)
                {
                    if (base64.Keys.Any((e) => e == node.managerId))
                        node.headIconBase64 = base64[node.managerId];
                    else
                    {
                        node.headIconBase64 = _fileService.GetImageBase64(node.headIcon);
                        base64.Add(node.managerId, node.headIconBase64);
                    }
                }
            }
            if (!string.IsNullOrWhiteSpace(node.responsibilityFilePath))
                node.responsibilityFileName = node.responsibilityFilePath.Split("{@yntk@}")[1];
            if (!string.IsNullOrWhiteSpace(node.targetFilePath))
                node.targetFileName = node.targetFilePath.Split("{@yntk@}")[1];
            if (!string.IsNullOrWhiteSpace(node.orientationFilePath))
                node.orientationFileName = node.orientationFilePath.Split("{@yntk@}")[1];

            return node;
        }

        /// <summary>
        /// 添加机构
        /// </summary>
        /// <param name="input">添加机构请求模型</param>
        /// <returns></returns>
        [HttpPost("add")]
        public async Task Add([FromBody] AddMechanismRequestModel input)
        {
            var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
            var userId = user.Value;
            string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
            //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
            var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;
            if (authenticationType != "2" && authenticationType != "3")
                throw YNTKException.Oh(ErrorCode.D1016);

            #region 唯一信息验证
            if((await GetMechanismInfoAsync(r=>r.Name==input.name && 
            r.OrganizeId==organizeId && r.ParentId==input.parentId && r.DeleteMark==null))!=null)
                throw YNTKException.Oh(ErrorCode.D2029);
            if ((await GetMechanismInfoAsync(r => r.Code == input.code && 
            r.OrganizeId == organizeId && r.ParentId == input.parentId && r.DeleteMark == null))!=null)
                throw YNTKException.Oh(ErrorCode.D2030);
            #endregion

            var entity = input.Adapt<MechanismEntity>();
            entity.Type = input.type.GetHashCode();
            entity.OrganizeId = organizeId;

           //sqlserver保存机构信息          
            var isOk = await _mechanismRepository.Context.Insertable(entity)
               .CallEntityMethod(m => m.Creator()).ExecuteReturnEntityAsync();
            _ = isOk ?? throw YNTKException.Oh(ErrorCode.D2031);

            //mogodb保存机构信息
            entity = isOk;
            var result = await _mechanismMongoDbRepository.AddAsync(entity, _collectionName);
            if (!result) throw YNTKException.Oh("mongodb保存机构信息失败！");

            if (!string.IsNullOrWhiteSpace(input.managerId))
            {
                //用户被设置为机构主管更新用户所属机构
                string mechanismId =await GetIdAsync(isOk.Id, organizeId);
                await _tkUsersService.UpdateUserMechanismAsync(input.managerId, mechanismId);
            }
        }

        /// <summary>
        /// 修改机构
        /// </summary>
        /// <param name="input">修改机构请求模型</param>
        /// <returns></returns>
        [HttpPut("update")]
        public async Task Update([FromBody] UpdateMechanismRequestModel input)
        {
            var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
            var userId = user.Value;
            string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
            //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
            var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;
            if (authenticationType != "2" && authenticationType != "3")
                throw YNTKException.Oh(ErrorCode.D1016);

            #region 唯一信息验证
            var entity = await GetMechanismInfoAsync(r => r.Id == input.id && r.DeleteMark == null);
            if (entity == null) throw YNTKException.Oh(ErrorCode.D2032);
            if(entity.OrganizeId!= organizeId) throw YNTKException.Oh(ErrorCode.D1016);
            if ((await GetMechanismInfoAsync(r => r.Name == input.name && r.Id!=input.id &&  
            r.OrganizeId == organizeId && r.ParentId == input.parentId && r.DeleteMark == null))!=null)
                throw YNTKException.Oh(ErrorCode.D2029);
            if ((await GetMechanismInfoAsync(r => r.Code == input.code && r.Id!=input.id &&  
            r.OrganizeId == organizeId && r.ParentId == input.parentId && r.DeleteMark == null))!=null)
                throw YNTKException.Oh(ErrorCode.D2030);
            #endregion
           
            //var entity = input.Adapt<MechanismEntity>();
            entity = input.Mapper(entity);
            entity.Type = input.type.GetHashCode();
            //entity.OrganizeId = organizeId;

            //sqlserver保存机构信息
            var isOK = await _mechanismRepository.Context.Updateable(entity)
              .IgnoreColumns(ignoreAllNullColumns: true)
              .CallEntityMethod(m => m.LastModify()).ExecuteCommandAsync();
            if (!(isOK > 0)) throw YNTKException.Oh(ErrorCode.D2033);

            //mongodb保存机构信息
            var update = await _mechanismMongoDbRepository.UpdateAsync(entity, _collectionName, m => m.Id == entity.Id);
            if (!(update.ModifiedCount > 0)) throw YNTKException.Oh("mongodb保存机构信息失败！");                    

            if (!string.IsNullOrWhiteSpace(input.managerId))
            {
                //用户被设置为机构主管更新用户所属机构
                string mechanismId = await GetIdAsync(input.id, organizeId);
                await _tkUsersService.UpdateUserMechanismAsync(input.managerId, mechanismId);
            }
        }

        /// <summary>
        /// 删除机构
        /// </summary>
        /// <param name="id">机构id</param>
        /// <returns></returns>
        [HttpDelete("delete/{id}")]
        public async Task Delete([Required] string id)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                var userId = user.Value;
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
                var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;
                if (authenticationType != "2" && authenticationType != "3")
                    throw YNTKException.Oh(ErrorCode.D1016);

                var entity = await GetMechanismInfoAsync(r => r.Id == id && r.DeleteMark == null);
                if (entity == null) throw YNTKException.Oh(ErrorCode.D2032);
                if (entity.OrganizeId != organizeId) throw YNTKException.Oh(ErrorCode.D1016);

                _mechanismRepository.Ado.BeginTran();
                //先从sqlserver中删除
                var isOk = await _mechanismRepository.Context.Deleteable(entity).ExecuteCommandAsync();
                if (!(isOk > 0)) throw YNTKException.Oh(ErrorCode.D2034);

                //再从mongodb中删除
                var delete = await _mechanismMongoDbRepository.DeleteAsync(_collectionName, m => m.Id == id);
                if (!(delete > 0)) throw YNTKException.Oh("mongodb删除机构失败");

                //将直属下级上移
                var childrens = await GetMechanismListAsync(r => r.ParentId == entity.Id && r.DeleteMark == null);
                if (childrens.Any())
                {
                    childrens.ForEach(children =>
                    {
                        children.ParentId = entity.ParentId;
                    });
                    await _mechanismRepository.Context.Updateable(childrens).ExecuteCommandAsync();
                    await _mechanismMongoDbRepository.UpdateManayAsync(childrens, _collectionName);
                }
                _mechanismRepository.Ado.CommitTran();
            }
            catch (Exception ex)
            {
                _mechanismRepository.Ado.RollbackTran();
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"删除机构发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 更新机构状态(启用/禁用)
        /// </summary>
        /// <param name="id">机构id</param>
        /// <returns></returns>
        [HttpPut("state/{id}")]
        public async Task UpdateState([Required] string id)
        {
            var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
            var userId = user.Value;
            string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
            //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
            var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;
            if (authenticationType != "2" && authenticationType != "3")
                throw YNTKException.Oh(ErrorCode.D1016);

            var entity = await GetMechanismInfoAsync(r => r.Id == id && r.DeleteMark == null);
            if (entity == null) throw YNTKException.Oh(ErrorCode.D2032);
            if (entity.OrganizeId != organizeId) throw YNTKException.Oh(ErrorCode.D1016);

            //更新sqlserver中机构状态
            var isOk = await _mechanismRepository.Context.Updateable<MechanismEntity>().SetColumns(it => new MechanismEntity()
            {
                EnabledMark = SqlFunc.IIF(it.EnabledMark == 1, 0, 1),
                LastModifyUserId = userId,
                LastModifyTime = SqlFunc.GetDate()
            }).Where(it => it.Id == id).ExecuteCommandAsync();
            if (!(isOk > 0))
                throw YNTKException.Oh(ErrorCode.D2035);

            //更新mongodb中友情链接状态
            entity.EnabledMark = entity.EnabledMark == 1 ? 0 : 1;
            entity.LastModifyTime = DateTime.Now;
            entity.LastModifyUserId = userId;
            var update = await _mechanismMongoDbRepository.UpdateAsync(entity, _collectionName, m => m.Id == entity.Id);
            if (!(update.ModifiedCount > 0)) throw YNTKException.Oh("mongodb更新机构状态失败");
        }

        #region 工作台
        /// <summary>
        /// 【工作台专用】获取当前登录用户所属机构树结构数据(包括自己和所有下级机构)
        /// </summary>
        /// <returns></returns>
        [HttpGet("workbench/gets")]
        public async Task<TkResult<List<MechanismTreeDto>>> GetList()
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                string mechanismId = user.Subject.FindFirst(ClaimConst.MECHANISMID).Value;

                var treeList = new List<MechanismTreeDto>();
                if (string.IsNullOrWhiteSpace(mechanismId) || mechanismId== "jg000000")
                    return TkResult<List<MechanismTreeDto>>.Success(treeList);

                //当前组织下全部机构数据
                var mechanismAllList = await db.Queryable<MechanismEntity, UserEntity>((a, b) =>
                new JoinQueryInfos(JoinType.Left, b.Id == a.ManagerId))
                    .Select((a, b) => new {
                        OrganizeId=a.OrganizeId,Id = a.Id, ParentId = a.ParentId,
                        Name = a.Name, Code = a.Code, Description = a.Description,HeadIcon=b.HeadIcon,
                        EnabledMark = a.EnabledMark, CreatorTime = a.CreatorTime,ManagerId=a.ManagerId,
                        ManagerName = SqlFunc.MergeString(b.RealName, "/", b.Account,"/",b.MobilePhone),
                        SortCode = a.SortCode, Type = a.Type, DeleteMark = a.DeleteMark,
                        Responsibility=a.Responsibility,Target=a.Target,
                        ResponsibilityFilePath=a.ResponsibilityFilePath,
                        TargetFilePath=a.TargetFilePath,
                        OrientationFilePath = a.OrientationFilePath
                    }).MergeTable()
                    .Where(t => t.OrganizeId == organizeId && t.DeleteMark == null)
                    .OrderBy(o => o.SortCode).OrderByDescending(o=>o.CreatorTime)
                    .Select<MechanismTreeDto>().ToListAsync();

                if (mechanismAllList.Any())
                {                  
                    treeList = mechanismAllList.TreeChildNode(mechanismId.Split(',').Last(), t => t.id, t => t.parentId);
                    treeList = treeList.OrderBy(r => r.sortCode).ToList();
                     var managerIds = new List<string>();
                    managerIds = treeList.Where(r => !string.IsNullOrWhiteSpace(r.managerId))
                       ?.ToList()?.Select(r => r.managerId)?.Distinct()?.ToList();
                    var managerList = await _tkUsersService.GetUserListByIds(managerIds);
                    var manager = new UserEntity();
                    var base64 = new Dictionary<string, string>() { { "xxxxx", "" } };
                    treeList.ForEach(item =>
                    {
                        item.typeText = EnumHelper.GetEnumDescriptionString
                        (item.type, typeof(MechanismTypeEnum));
                        if (!string.IsNullOrWhiteSpace(item.managerId))
                        {
                            manager = managerList?.FirstOrDefault(r => r.Id == item.managerId);
                            item.managerName = manager?.RealName;
                            item.headIcon = manager?.HeadIcon;
                            if (!string.IsNullOrWhiteSpace(item.headIcon))
                            {
                                if (base64.Keys.Any((e) => e == item.managerId))
                                    item.headIconBase64 = base64[item.managerId];
                                else
                                {
                                    item.headIconBase64 = _fileService.GetImageBase64(item.headIcon);
                                    base64.Add(item.managerId, item.headIconBase64);
                                }
                            }
                        }
                        if (!string.IsNullOrWhiteSpace(item.responsibilityFilePath))
                            item.responsibilityFileName = item.responsibilityFilePath.Split("{@yntk@}")[1];
                        if (!string.IsNullOrWhiteSpace(item.targetFilePath))
                            item.targetFileName = item.targetFilePath.Split("{@yntk@}")[1];
                        if (!string.IsNullOrWhiteSpace(item.orientationFilePath))
                            item.orientationFileName = item.orientationFilePath.Split("{@yntk@}")[1];
                    });
                    treeList = treeList.ToTree();
                }
                return TkResult<List<MechanismTreeDto>>.Success(treeList);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"【工作台专用】获取当前登录用户所属机构树结构数据(包括自己和所有下级机构)发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 【工作台专用】获取当前机构id获取机构树结构数据(包括自己和所有下级机构)
        /// </summary>
        /// <returns></returns>
        [HttpGet("workbench/getsons")]
        public async Task<TkResult<List<MechanismTreeDto>>> GetSonList([Required] string id)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                id =await GetIdAsync(id, organizeId);

                var treeList = new List<MechanismTreeDto>();
                if (string.IsNullOrWhiteSpace(id) || id == "jg000000")
                    return TkResult<List<MechanismTreeDto>>.Success(treeList);

                //当前组织下全部机构数据
                var mechanismAllList = await db.Queryable<MechanismEntity, UserEntity>((a, b) =>
                new JoinQueryInfos(JoinType.Left, b.Id == a.ManagerId))
                    .Select((a, b) => new {
                        OrganizeId = a.OrganizeId,
                        Id = a.Id,
                        ParentId = a.ParentId,
                        Name = a.Name,
                        Code = a.Code,
                        Description = a.Description,
                        HeadIcon = b.HeadIcon,
                        EnabledMark = a.EnabledMark,
                        CreatorTime = a.CreatorTime,
                        ManagerId = a.ManagerId,
                        ManagerName = SqlFunc.MergeString(b.RealName, "/", b.Account, "/", b.MobilePhone),
                        SortCode = a.SortCode,
                        Type = a.Type,
                        DeleteMark = a.DeleteMark,
                        Responsibility = a.Responsibility,
                        Target = a.Target,
                        ResponsibilityFilePath = a.ResponsibilityFilePath,
                        TargetFilePath = a.TargetFilePath,
                        OrientationFilePath = a.OrientationFilePath
                    }).MergeTable()
                    .Where(t => t.OrganizeId == organizeId && t.DeleteMark == null)
                    .OrderBy(o => o.SortCode).OrderByDescending(o => o.CreatorTime)
                    .Select<MechanismTreeDto>().ToListAsync();

                if (mechanismAllList.Any())
                {
                    treeList = mechanismAllList.TreeChildNode(id.Split(',').Last(), t => t.id, t => t.parentId);
                    treeList = treeList.OrderBy(r => r.sortCode).ToList();
                    var managerIds = new List<string>();
                    managerIds = treeList.Where(r => !string.IsNullOrWhiteSpace(r.managerId))
                      ?.ToList()?.Select(r => r.managerId)?.Distinct()?.ToList();
                    var managerList = await _tkUsersService.GetUserListByIds(managerIds);
                    var manager = new UserEntity();
                    var base64 = new Dictionary<string, string>() { { "xxxxx", "" } };
                    treeList.ForEach(item =>
                    {
                        item.typeText = EnumHelper.GetEnumDescriptionString
                        (item.type, typeof(MechanismTypeEnum));
                        if (!string.IsNullOrWhiteSpace(item.managerId))
                        {
                            manager = managerList?.FirstOrDefault(r => r.Id == item.managerId);
                            item.managerName = manager?.RealName;
                            item.headIcon = manager?.HeadIcon;
                            if (!string.IsNullOrWhiteSpace(item.headIcon))
                            {
                                if (base64.Keys.Any((e) => e == item.managerId))
                                    item.headIconBase64 = base64[item.managerId];
                                else
                                {
                                    item.headIconBase64 = _fileService.GetImageBase64(item.headIcon);
                                    base64.Add(item.managerId, item.headIconBase64);
                                }
                            }
                        }
                        if (!string.IsNullOrWhiteSpace(item.responsibilityFilePath))
                            item.responsibilityFileName = item.responsibilityFilePath.Split("{@yntk@}")[1];
                        if (!string.IsNullOrWhiteSpace(item.targetFilePath))
                            item.targetFileName = item.targetFilePath.Split("{@yntk@}")[1];
                        if (!string.IsNullOrWhiteSpace(item.orientationFilePath))
                            item.orientationFileName = item.orientationFilePath.Split("{@yntk@}")[1];
                    });
                    treeList = treeList.ToTree();
                }
                return TkResult<List<MechanismTreeDto>>.Success(treeList);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"【工作台专用】获取当前机构id获取机构树结构数据(包括自己和所有下级机构)发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 【工作台专用】保存机构文件(职责：岗位说明书,目标：完成情况统计)
        /// </summary>
        /// <param name="save">保存机构文件(职责：岗位说明书,目标：完成情况统计)请求模型</param>
        /// <returns></returns>
        [HttpPut("workbench/replace/file")]
        public async Task SaveMechanismFile([FromBody] SaveMechanismFileRequestModel save)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                string mechanismId = user.Subject.FindFirst(ClaimConst.MECHANISMID).Value;

                if (mechanismId.Contains(',') && !save.id.Contains(','))
                    mechanismId = mechanismId.Split(',').Last();
                if (save.id!= mechanismId || mechanismId== "jg000000")
                    throw YNTKException.Oh(ErrorCode.D1016);
                var entity = await _mechanismRepository.FirstOrDefaultAsync(r => r.Id == save.id && r.DeleteMark == null);
                if (entity == null) throw YNTKException.Oh(ErrorCode.D2032);
                if (entity.OrganizeId != organizeId) throw YNTKException.Oh(ErrorCode.D1016);
                //0.职责：岗位说明书  1.目标：完成情况统计 2.定置定位文件服务器存储路径
                string oldFilePath = "";
                if (save.type == 0)
                {
                    if (!string.IsNullOrWhiteSpace(entity.ResponsibilityFilePath) && entity.ResponsibilityFilePath!= save.storagePath)
                        oldFilePath = entity.ResponsibilityFilePath;
                    entity.ResponsibilityFilePath = save.storagePath;
                }
                else if(save.type==1)
                {
                    if (!string.IsNullOrWhiteSpace(entity.TargetFilePath) && entity.TargetFilePath != save.storagePath)
                        oldFilePath = entity.TargetFilePath;
                    entity.TargetFilePath = save.storagePath;
                }
                else
                {
                    if (!string.IsNullOrWhiteSpace(entity.OrientationFilePath) && entity.OrientationFilePath != save.storagePath)
                        oldFilePath = entity.OrientationFilePath;
                    entity.OrientationFilePath = save.storagePath;
                }
                entity.LastModifyTime = DateTime.Now;
                entity.LastModifyUserId = userId;
                //保存到sqlserver
                var isOK = await _mechanismRepository.Context.Updateable(entity).ExecuteCommandAsync();
                if (!(isOK > 0)) throw YNTKException.Oh($"保存机构“{entity.Name}”{(save.type == 0 ? "职责：岗位说明书" : "目标：完成情况统计")}文件失败！");

                //保存到mongodb
                var update = await _mechanismMongoDbRepository.UpdateAsync(entity, _collectionName, m => m.Id == entity.Id);
                if (!(update.ModifiedCount > 0)) throw YNTKException.Oh($"mongodb保存机构“{entity.Name}”{(save.type == 0 ? "职责：岗位说明书" : "目标：完成情况统计")}文件失败！");

                if (!string.IsNullOrWhiteSpace(oldFilePath)) _fileService.DeleteSingleFile(oldFilePath);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"【工作台专用】保存机构{(save.type==0 ? "职责：岗位说明书" : "目标：完成情况统计")}文件发生异常：{ex.Message}");
            }
        }
        #endregion

        #region 机构职责目标
        /// <summary>
        /// 分页获取职责/目标数据
        /// </summary>
        /// <param name="query">查询机构职责/目标请求模型</param>
        /// <returns></returns>
        [HttpPost("responsibilitytarget/gets")]
        public async Task<TkPageResult<ResponsibilityTargetListDto>> GetTargetList([FromBody] QueryResponsibilityTargetFilterRequestModel query)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                string mechanismId = user.Subject.FindFirst(ClaimConst.MECHANISMID).Value;

                #region 拼接查询条件
                Expression<Func<ResponsibilityTargetEntity, bool>> where = m =>
                m.OrganizeId == organizeId && m.Type==query.type;
                if (!string.IsNullOrWhiteSpace(query.mechanismId))
                {
                    string queryMechanismId = await GetIdAsync(query.mechanismId, organizeId);
                    where = where.And(m => m.MechanismId == queryMechanismId);
                }
                else
                {
                    if(!string.IsNullOrWhiteSpace(mechanismId) && mechanismId!= "jg000000")
                        where = where.And(m => m.MechanismId == mechanismId);
                }
                if (query.startTime != null) where = where.And(m => m.CreatorTime >= query.startTime);
                if (query.endTime != null) where = where.And(m => m.CreatorTime <= query.endTime);
                #endregion

                var pageList = new SqlSugarPagedList<ResponsibilityTargetListDto>();

                #region 先从mongodb中获取职责/目标数据
                //排序生成器
                var builderSort = Builders<ResponsibilityTargetEntity>.Sort;
                //排序约束   Ascending 正序    Descending 倒序
                var sort = builderSort.Descending(r => r.CreatorTime);
                //Item1.结果集 Item2.总条数 Item3.总页数
                (List<ResponsibilityTargetEntity>, int, int) result =
                    await _targetMongoDbRepository.GetListAsync(_target,
                    where, query.currentPage, query.pageSize, null, sort);
                pageList.list = result.Item1.Adapt<List<ResponsibilityTargetListDto>>();
                pageList.pagination = new PagedModel()
                {
                    PageIndex = query.currentPage,
                    PageSize = query.pageSize,
                    Total = result.Item2,
                    PageCount = result.Item3
                };
                #endregion

                if (pageList.list == null || pageList.list.Count() <= 0)
                {
                    #region 再从sqlserver中获取职责/目标数据
                    var sqlResult = await _targetRepository.Entities.Where(where)
                         .OrderBy(r => r.CreatorTime, OrderByType.Desc)
                         .ToPagedListAsync(query.currentPage, query.pageSize);
                    pageList.list = sqlResult.list.Adapt<List<ResponsibilityTargetListDto>>();
                    pageList.pagination = sqlResult.pagination;
                    #endregion
                }

                #region 处理文件清单返回数据
                if (pageList.list.Any())
                {
                    var mechanismIds = pageList.list.Where(r => !string.IsNullOrWhiteSpace(r.mechanismId))
                        ?.Select(r => r.mechanismId.Split(',').ToList())
                        ?.SelectMany(r => r).Distinct().ToList();
                    var mechanisms = !mechanismIds.Any() ? new List<MechanismEntity>() :
                        await GetMechanismListAsync(null, mechanismIds);
                    var userIds = pageList.list.Select(r => r.creatorUserId).Distinct().ToList();
                    var users = await _tkUsersService.GetUserListByIds(userIds);
                    pageList.list.ForEach(item =>
                    {
                        if (!string.IsNullOrWhiteSpace(item.mechanismId))
                        {
                            item.mechanismName = string.Join('/', mechanisms
                                ?.Where(r => item.mechanismId.Split(',').ToList().Contains(r.Id))
                                ?.Select(r => r.Name)?.ToList());
                        }
                        if (!string.IsNullOrWhiteSpace(item.creatorUserId))
                            item.creatorUserName = users?.FirstOrDefault(r => r.Id == item.creatorUserId)?.RealName;
                    });
                }
                #endregion

                return TkPageResult<ResponsibilityTargetListDto>.Success(pageList);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"分页获取{(query.type==0 ? "职责" : "目标")}数据发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 添加职责/目标
        /// </summary>
        /// <param name="input">添加机构职责/目标请求模型</param>
        /// <returns></returns>
        [HttpPut("responsibilitytarget/add")]
        public async Task AddResponsibilityTarget([FromBody] AddResponsibilityTargetRequestModel input)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                string mechanismId = user.Subject.FindFirst(ClaimConst.MECHANISMID).Value;
                var entity = input.Adapt<ResponsibilityTargetEntity>();
                entity.Id = YitIdHelper.NextId().ToString();
                entity.OrganizeId = organizeId;//所属组织id
                entity.MechanismId = mechanismId;
                entity.CreatorUserId = userId;
                entity.CreatorTime = DateTime.Now;
                var isOk = await _targetRepository.Context.Insertable(entity).ExecuteReturnEntityAsync();
                _ = isOk ?? throw YNTKException.Oh($"添加{(input.type == 0 ? "职责" : "目标")}失败");
                entity = isOk;
                var add = await _targetMongoDbRepository.AddAsync(entity, _target);
                if (!add) throw YNTKException.Oh($"mongodb添加{(input.type == 0 ? "职责" : "目标")}失败");
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"添加{(input.type == 0 ? "职责" : "目标")}发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 删除职责/目标
        /// </summary>
        /// <param name="type">类型(0.职责 1.目标)</param>
        /// <param name="id">职责/目标id</param>
        /// <returns></returns>
        [HttpDelete("responsibilitytarget/delete/{type}/{id}")]
        public async Task DeleteResponsibilityTarget([Required] int type, [Required] string id)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string mechanismId = user.Subject.FindFirst(ClaimConst.MECHANISMID).Value;
                var entity = await _targetMongoDbRepository.GetAsync(_target, m => m.Id == id && m.Type==type);
                if (entity == null) entity = await _targetRepository.FirstOrDefaultAsync(r => r.Id == id && r.Type==type);
                if(entity.MechanismId!= mechanismId) throw YNTKException.Oh(ErrorCode.D1016);
                if (entity != null)
                {
                    await _targetRepository.DeleteAsync(r => r.Id == id);
                    await _targetMongoDbRepository.DeleteAsync(_target, m => m.Id == id);
                    //删除文件
                    string filePath = entity.FileDirectory + entity.SaveFileName;
                    _fileService.DeleteSingleFile(filePath);
                }
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"删除{(type == 0 ? "职责" : "目标")}发生异常：{ex.Message}");
            }
        }
        #endregion

        /// <summary>
        /// 同步机构数据(开发人员同步专用)
        /// </summary>
        /// <param name="type">0.sqlserver同步mongodb 1.mongodb同步sqlserver</param>
        /// <param name="organizeId">要同步的组织id</param>
        /// <returns></returns>
        [HttpPut("synchronous/{type}/{organizeId}")]
        public async Task Synchronous([Required] int type, [Required] string organizeId)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
                var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;
                if (authenticationType != "1" || (type != 0 && type != 1)) throw YNTKException.Oh(ErrorCode.D1016);
                _mechanismRepository.Ado.BeginTran();
                List<MechanismEntity> data = null;
                Expression<Func<MechanismEntity, bool>> where = r => r.DeleteMark == null;
                if (!string.IsNullOrWhiteSpace(organizeId)) where = where.And(r => r.OrganizeId == organizeId);
                if (type == 0)
                {
                    data = await _mechanismRepository.Entities.Where(where).ToListAsync();
                    if (data.Any())
                    {
                        //删除mongodb原数据
                        await _mechanismMongoDbRepository.DeleteAsync(_collectionName, where);
                        //保存到mongodb
                        var succeed = await _mechanismMongoDbRepository.AddListAsync(data, _collectionName);
                        if (!succeed) throw YNTKException.Oh("机构数据sqlserver同步mongodb失败");
                    }
                }
                if (type == 1)
                {
                    data = await _mechanismMongoDbRepository.GetListAsync(_collectionName, where);
                    if (data.Any())
                    {
                        //删除sqlserver原数据
                        await _mechanismRepository.DeleteAsync(where);
                        //保存到sqlserver                 
                        var isOk = await _mechanismRepository.Context.Insertable(data).ExecuteCommandAsync();
                        if (!(isOk > 0)) throw YNTKException.Oh("机构数据mongodb同步sqlserver失败");
                    }
                }
                _mechanismRepository.Ado.CommitTran();
            }
            catch (Exception ex)
            {
                _mechanismRepository.Ado.RollbackTran();
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"同步机构数据发生异常：{ex.Message}");
            }
        }




        /// <summary>
        /// 根据条件获取机构信息信息
        /// </summary>
        /// <param name="where">条件</param>
        /// <returns></returns>
        private async Task<MechanismEntity> GetMechanismInfoAsync(Expression<Func<MechanismEntity, bool>> where)
        {
            //从从mongodb中获取
            var entity = await _mechanismMongoDbRepository.GetAsync(_collectionName, where);
            //再从sqlserver中获取
            if (entity == null) entity = await _mechanismRepository.FirstOrDefaultAsync(where);
            return entity;
        }

        /// <summary>
        /// 根据条件获取机构数据
        /// </summary>
        /// <param name="where">条件</param>
        /// <returns></returns>
        private async Task<List<MechanismEntity>> GetMechanismListAsync(Expression<Func<MechanismEntity, bool>> where)
        {
            //从从mongodb中获取
            var result = await _mechanismMongoDbRepository.GetListAsync(_collectionName, where);
            //再从sqlserver中获取
            if (!result.Any()) result = await _mechanismRepository.Entities.Where(where).ToListAsync();
            return result;
        }

        /// <summary>
        /// 拼接所有父级id,包括自己
        /// </summary>
        /// <param name="data"></param>
        /// <param name="id"></param>
        /// <returns></returns>
        private string DisposeId(List<MechanismTreeListDto> data,string id)
        {
            if (id.Contains(",")) return id;
            if (!data.Any()) return id;
            //获取所有上级包括自己
            data = data.TreeWhere(r => r.id == id, r => r.id, r => r.parentId);
            //顺序反转
            data.Reverse();
            var ids = data.Select(r => r.id).ToList();
            id = string.Join(',', ids);
            return id;
        }

        #region PublicMethod
        /// <summary>
        /// 根据机构id获取机构信息
        /// </summary>
        /// <param name="id">机构id</param>
        /// <returns></returns>
        [NonAction]
        public async Task<MechanismEntity> GetMechanismInfoAsync(string id)
        {
            //先从mongodb中获取机构信息
            var entity = await _mechanismMongoDbRepository.GetAsync(_collectionName,m=>m.Id==id);
            //再从sqlserver中获取机构信息
            if (entity == null) entity = await _mechanismRepository.FirstOrDefaultAsync(r=>r.Id==id);
            return entity;
        }

        /// <summary>
        /// 获取机构数据
        /// </summary>
        /// <param name="organizeId">组织id</param>
        /// <param name="ids">机构id集合</param>
        /// <returns></returns>
        [NonAction]
        public async Task<List<MechanismEntity>> GetMechanismListAsync(string organizeId,List<string> ids)
        {
            var result = new List<MechanismEntity>();
            Expression<Func<MechanismEntity, bool>> where = r =>r.DeleteMark == null;
            if(!string.IsNullOrWhiteSpace(organizeId))
                where = r =>r.OrganizeId == organizeId;
            if (ids != null && ids.Count > 0)
                where = r => ids.Contains(r.Id);

            //从mongodb中获取机构数据
            result = await _mechanismMongoDbRepository.GetListAsync(_collectionName,where);
            if (result == null || result.Count <= 0)
            {
                //从sqlserver数据库中获取机构数据
                result = await _mechanismRepository.Entities.Where(where).ToListAsync();
            }
            return result;
        }

        /// <summary>
        /// 处理机构id拼接上所有父级id
        /// </summary>
        /// <param name="id">机构id</param>
        /// <param name="organizeId">组织id</param>
        /// <returns></returns>
        [NonAction]
        public async Task<string> GetIdAsync(string id,string organizeId)
        {
            if (id.Contains(",")) return id;
            var data = await _mechanismMongoDbRepository.GetListAsync(_collectionName, m => m.OrganizeId == organizeId && m.DeleteMark == null);
            if (!data.Any())
                data = await _mechanismRepository.Entities.Where(r => r.OrganizeId == organizeId && r.DeleteMark == null).ToListAsync();
            if (!data.Any()) return id;
            //获取所有上级包括自己
            data = data.TreeWhere(r=>r.Id==id,r=>r.Id,r=>r.ParentId);
            //顺序反转
            data.Reverse();
            var ids = data.Select(r => r.Id).ToList();
            id = string.Join(',', ids);
            return id;
        }

        /// <summary>
        /// 处理机构id拼接上所有父级id
        /// </summary>
        /// <param name="ids">id集合(最后一级的id)</param>
        /// <param name="organizeId">组织id</param>
        /// <returns>key.id  value.(Item1.拼接上所有父级的id,Item2.最后一级的机构名称)</returns>
        [NonAction]
        public async Task<Dictionary<string,(string,string)>> GetIdsAsync(List<string> ids, string organizeId)
        {
            var dic = new Dictionary<string, (string, string)>() { { "0", ("0", "") } };
            if (!ids.Any()) return null;
            dic = ids.ToDictionary(x => x, x => (x,""));
            var data = await _mechanismMongoDbRepository.GetListAsync(_collectionName, m => m.OrganizeId == organizeId && m.DeleteMark == null);
            if (!data.Any())
                data = await _mechanismRepository.Entities.Where(r => r.OrganizeId == organizeId && r.DeleteMark == null).ToListAsync();
            if (!data.Any()) return dic;
            var list = new List<MechanismEntity>();
            string id = "";
            foreach (KeyValuePair<string, (string, string)> item in dic)
            {
                id = item.Value.Item1;
                //获取所有上级包括自己
                list = data.TreeWhere(r => r.Id == id, r => r.Id, r => r.ParentId);
                //顺序反转
                list.Reverse();
                id = string.Join(',', list.Select(r => r.Id).ToList());
                dic[item.Key] = (id, list.Last().Name);
            }
            return dic;
        }
        #endregion

    }
}
